﻿using DataType;
using DataType.CustomEnumType;
using DataType.JudgeResults;
using DataType.MessageType;
using MapCalclator;
using OprsSimulator.OprAttributes;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OprsSimulator.Operators
{
    public class ArtilleryOpr : IOperator, ICommonAttris, IAttackAttris, IMoveAttris, IStateAttris, IReconnaissanceAttris, IDefendAttris
    {
        //ICommonAttris
        private int obj_id;
        private string name;
        private Color color;
        private OprType type;
        private OprSubType sub_type;
        private int value;
        private int blood;
        private int max_blood;

        public int ObjID { get => obj_id; }
        public string Name { get => name; }

        public Color Color { get => color; }

        public OprType Type { get => type; }

        public OprSubType Subtype { get => sub_type; }

        public int Value { get => value; }

        public int Blood { get => blood; set => blood = value; }

        public int MaxBlood { get => max_blood; }

        //IAttackAttris
        private bool a1;
        private List<WeaponType> carry_weapon_ids = new List<WeaponType>();
        private Dictionary<BulletType, int> remain_bullet_nums = new Dictionary<BulletType, int>();
        private Dictionary<BulletType, int> remain_bullet_nums_bk = new Dictionary<BulletType, int>();
        private bool guide_ability;
        private int weapon_cool_time;
        private int weapon_unfold_time;
        private int weapon_unfold_state;
        public bool A1 { get => a1; }

        public List<WeaponType> CarryWeaponIDs { get => carry_weapon_ids; }

        public Dictionary<BulletType, int> RemainBulletNums { get => remain_bullet_nums; set => remain_bullet_nums = value; }
        public Dictionary<BulletType, int> RemainBulletNumsBK { get => remain_bullet_nums_bk; set => remain_bullet_nums_bk = value; }

        public bool GuideAbility { get => guide_ability; }

        public int WeaponCoolTime { get => weapon_cool_time; set => weapon_cool_time = value; }
        public int WeaponUnfoldTime { get => weapon_unfold_time; set => weapon_unfold_time = value; }
        public int WeaponUnfoldState { get => weapon_unfold_state; set => weapon_unfold_state = value; }
        //IMoveAttris
        private int basic_speed;
        private MoveStateType move_state;
        private int cur_hex;
        private float cur_pos;
        private int speed;
        private int move_to_stop_remain_time;
        private bool can_to_move;
        private bool flag_force_stop;
        private bool stop;
        private List<int> move_path;
        private int tire;
        private int tire_accumulate_time;
        private bool on_board;
        private int car;
        private int launcher;
        private int get_on_remain_time;
        private List<int> get_on_partner_id;
        private int get_off_remain_time;
        private List<int> get_off_partner_id;
        private int change_state_remain_time;
        private MoveStateType target_state;

        public int BasicSpeed { get => basic_speed; }

        public MoveStateType MoveState { get => move_state; set => move_state = value; }
        public int CurHex { get => cur_hex; set => cur_hex = value; }
        public float CurPos { get => cur_pos; set => cur_pos = value; }
        public int Speed { get => speed; set => speed = value; }
        public int MoveToStopRemainTime { get => move_to_stop_remain_time; set => move_to_stop_remain_time = value; }
        public bool CanToMove { get => can_to_move; set => can_to_move = value; }
        public bool FlagForceStop { get => flag_force_stop; set => flag_force_stop = value; }
        public bool Stop { get => stop; set => stop = value; }
        public List<int> MovePath { get => move_path; set => move_path = value; }
        public int Tire { get => tire; set => tire = value; }
        public int TireAccumulateTime { get => tire_accumulate_time; set => tire_accumulate_time = value; }
        public bool OnBoard { get => on_board; set => on_board = value; }
        public int Car { get => car; set => car = value; }
        public int Launcher { get => launcher; set => launcher = value; }
        public int GetOnRemainTime { get => get_on_remain_time; set => get_on_remain_time = value; }
        public List<int> GetOnPartnerId { get => get_on_partner_id; set => get_on_partner_id = value; }
        public int GetOffRemainTime { get => get_off_remain_time; set => get_off_remain_time = value; }
        public List<int> GetOffPartnerId { get => get_off_partner_id; set => get_off_partner_id = value; }
        public int ChangeStateRemainTime { get => change_state_remain_time; set => change_state_remain_time = value; }
        public MoveStateType TargetState { get => target_state; set => target_state = value; }
        //IStateAttris
        private bool stack;
        private bool keep;
        private int keep_remain_time;
        private bool lose_control;
        private int alive_remain_time;
        public bool Stack { get => stack; set => stack = value; }
        public bool Keep { get => keep; set => keep = value; }
        public int KeepRemainTime { get => keep_remain_time; set => keep_remain_time = value; }
        public bool LoseControl { get => lose_control; set => lose_control = value; }
        public int AliveRemainTime { get => alive_remain_time; set => alive_remain_time = value; }
        //IReconnaissanceAttris
        private Dictionary<OprSubType, int> observe_distance;
        private List<int> see_enemy_bop_ids;
        public Dictionary<OprSubType, int> ObserveDistance { get => observe_distance; }

        public List<int> SeeEnemyBopIDs { get => see_enemy_bop_ids; set => see_enemy_bop_ids = value; }
        //IDefendAttris
        private ArmorType armor;
        public ArmorType Armor { get => armor; set => armor = value; }

        public void SetUp(OperatorMsg operatorMsg)
        {
            //ICommonAttris
            obj_id = operatorMsg.obj_id;
            name = operatorMsg.name;
            color = (Color)operatorMsg.color;
            type = (OprType)operatorMsg.type;
            sub_type = (OprSubType)operatorMsg.sub_type;
            value = operatorMsg.value;
            blood = operatorMsg.blood;
            max_blood = operatorMsg.max_blood;
            //IAttackAttris
            a1 = operatorMsg.A1;
            foreach (int id in operatorMsg.carry_weapon_ids)
            {
                carry_weapon_ids.Add((WeaponType)id);
            }
            foreach (var remain_bullet_num in operatorMsg.remain_bullet_nums)
            {
                remain_bullet_nums.Add((BulletType)remain_bullet_num.Key, remain_bullet_num.Value);
            }
            foreach (var remain_bullet_num_bk in operatorMsg.remain_bullet_nums_bk ?? new Dictionary<int, int>())
            {
                remain_bullet_nums_bk.Add((BulletType)remain_bullet_num_bk.Key, remain_bullet_num_bk.Value);
            }
            guide_ability = operatorMsg.guide_ability;
            weapon_cool_time = operatorMsg.weapon_cool_time;
            weapon_unfold_time = operatorMsg.weapon_unfold_time;
            weapon_unfold_state = operatorMsg.weapon_unfold_state;
            //IMoveAttris
            basic_speed = operatorMsg.basic_speed;
            move_state = (MoveStateType)operatorMsg.move_state;
            cur_hex = operatorMsg.cur_hex;
            cur_pos = operatorMsg.cur_pos;
            speed = operatorMsg.speed;
            move_to_stop_remain_time = operatorMsg.move_to_stop_remain_time;
            can_to_move = operatorMsg.can_to_move;
            flag_force_stop = operatorMsg.flag_force_stop;
            stop = operatorMsg.stop;
            move_path = operatorMsg.move_path;
            tire = operatorMsg.tire;
            tire_accumulate_time = operatorMsg.tire_accumulate_time;
            on_board = operatorMsg.on_board;
            car = operatorMsg.car ?? -1;
            launcher = operatorMsg.launcher ?? -1;
            get_on_remain_time = operatorMsg.get_on_remain_time;
            get_on_partner_id = operatorMsg.get_on_partner_id;
            get_off_remain_time = operatorMsg.get_off_remain_time;
            get_off_partner_id = operatorMsg.get_off_partner_id;
            change_state_remain_time = operatorMsg.change_state_remain_time;
            target_state = (MoveStateType)operatorMsg.target_state;
            //IStateAttris
            stack = operatorMsg.stack;
            keep = operatorMsg.keep;
            keep_remain_time = operatorMsg.keep_remain_time;
            lose_control = operatorMsg.lose_control;
            alive_remain_time = operatorMsg.alive_remain_time;
            //IReconnaissanceAttris
            if (operatorMsg.observe_distance == null)// 如果无值，按规则赋值
            {
                observe_distance = new Dictionary<OprSubType, int>
                {
                    {OprSubType.Tank, 25},
                    {OprSubType.IFV, 25},
                    {OprSubType.Infantry, 10},
                    {OprSubType.Artillery, 10},
                    {OprSubType.UGV, 25},
                    {OprSubType.Drone, 1},
                    {OprSubType.Helicopter, 25},
                    {OprSubType.CruisingMissile, 1},
                };
            }
            else
            {
                foreach (var od in operatorMsg.observe_distance)
                {
                    observe_distance.Add((OprSubType)od.Key, od.Value);
                }
            }
            see_enemy_bop_ids = operatorMsg.see_enemy_bop_ids ?? new List<int>();
            //IDefendAttris
            armor = (ArmorType)operatorMsg.armor;
        }

        public void UpdataStandaloneAttris(List<IJudgeResult> judge_results, Map map)
        {
            foreach (IJudgeResult judge_result in judge_results)// 根据裁决结果更新属性
            {
                if (judge_result.ActionType == ActionType.Shoot || judge_result.ActionType == ActionType.GuideShoot)//被直瞄射击
                {
                    UpdateShootAttris(judge_result);
                }
                else if (!judge_result.IsSuccess) continue;// 裁决失败的裁决结果跳过，跳过
                else
                {
                    if (judge_result.ObjID != obj_id) continue;  // 不是这个算子的裁决结果，跳过
                    if (judge_result.ActionType == ActionType.ChangeState) UpdateChangeStateAttris(judge_result);// 切换状态裁决结果更新
                    else if (judge_result.ActionType == ActionType.WeaponLock) UpdateWeaponLockAttris(judge_result);// 武器锁定裁决结果更新
                    else if (judge_result.ActionType == ActionType.WeaponUnfold) UpdateWeaponUnfoldAttris(judge_result);// 武器展开裁决结果更新
                    else if (judge_result.ActionType == ActionType.JMPlan) UpdateJMPlanAttris(judge_result);// 间瞄计划裁决结果更新
                    else if (judge_result.ActionType == ActionType.CancelJMPlan) UpdateCancelJMPlanAttris(judge_result);// 取消间瞄计划裁决结果更新
                }
            }
            PutForwardObservation(map);// 更新持续性动作，如机动和各种倒计时等
        }
        public void UpdateAssociatedAttris(List<IOperator> oprs, List<IOperator> passengers, Map map)
        {
            UpdataStackAttris(oprs);// 检查堆叠
            UpdataSeeEnemyAttris(oprs, map);// 更新观察敌方算子列表
        }

        public Dictionary<int, List<ActionMsg>> ConfirmValidActions(List<OperatorMsg> oprs, CityMsg[] cities, Map map, ShootJudgeTable shootJudgeTable, List<IOperator> passengers)
        {
            Dictionary<int, List<ActionMsg>> individualValidActions = new Dictionary<int, List<ActionMsg>>();// 保存本算子的全部合法动作，用于返回

            // 判断算子是否能执行间瞄计划
            if (weapon_cool_time == 0 && weapon_unfold_state == 1 && change_state_remain_time <= 0 && weapon_unfold_time <= 0)// 武器展开，冷却完毕，没有正在执行其他动作
            {
                List<ActionMsg> jm_plan_action = new List<ActionMsg>();// 存储动作
                foreach (var id in carry_weapon_ids)// 暂时是添加了全部武器
                {
                    jm_plan_action.Add(new ActionMsg { type = (int)ActionType.JMPlan, obj_id = obj_id, weapon_id = (int)id});// 动作类型、算子id、武器id
                }               
                individualValidActions.Add((int)ActionType.JMPlan, jm_plan_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            // 判断算子是否能取消间瞄计划
            if (weapon_cool_time >= 150 && change_state_remain_time <= 0 && weapon_unfold_time <= 0)// 间瞄火力飞行时间小于150秒（用300秒的武器冷却时间计时），且没有在执行其他动作
            {
                List<ActionMsg> cancel_jm_plan_action = new List<ActionMsg>();// 新建动作
                cancel_jm_plan_action.Add(new ActionMsg { type = (int)ActionType.CancelJMPlan, obj_id = obj_id });// 动作类型、算子id
                individualValidActions.Add((int)ActionType.CancelJMPlan, cancel_jm_plan_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            // 判断是否能切换状态
            List<ActionMsg> change_state_action = new List<ActionMsg>();
            // 1.判断能否转正常机动状态
            if ((move_state == MoveStateType.HalfSpeed || move_state == MoveStateType.Shelt) && change_state_remain_time <= 0 && weapon_unfold_time <= 0)// 处于半速或掩蔽，且没有在执行其他动作（炮兵不可机动，没做速度判断）
            {                
                change_state_action.Add(
                new ActionMsg { type = (int)ActionType.ChangeState, obj_id = obj_id, target_state = (int)MoveStateType.Normal }// 动作类型、算子id、目标状态
                );               
            }

            // 2.判断能否转掩蔽状态
            if (!keep) // 不能处于压制状态
            {
                if ((move_state == MoveStateType.Normal || move_state == MoveStateType.HalfSpeed) && change_state_remain_time <= 0 && weapon_unfold_time <= 0)  // 判断是否处于正常状态（炮兵不可机动，没做速度判断）
                {
                    change_state_action.Add(
                    new ActionMsg { type = (int)ActionType.ChangeState, obj_id = obj_id, target_state = (int)MoveStateType.Shelt }// 动作类型、算子id、目标状态
                    );
                }
            }
            // 3.判断能否转半速状态
            if ((move_state == MoveStateType.Normal || move_state == MoveStateType.Shelt) && change_state_remain_time <= 0 && weapon_unfold_time <= 0)  // 判断是否处于正常状态
            {
                change_state_action.Add(
                new ActionMsg { type = (int)ActionType.ChangeState, obj_id = obj_id, target_state = (int)MoveStateType.HalfSpeed }// 动作类型、算子id、目标状态
                );                
            }
            // 如果change_state_action不为空，添加
            if (change_state_action.Count > 0) individualValidActions.Add((int)ActionType.ChangeState, change_state_action);// 动作集合添加进合法动作以该动作类型为键的值中

            // 判断能否锁定武器
            if (weapon_unfold_state == 1)// 武器已经展开
            {
                if (stop & speed <= 0 & move_to_stop_remain_time <= 0 & weapon_unfold_time <= 0 && change_state_remain_time <= 0)// 没有在执行其他动作
                {
                    List<ActionMsg> weapon_lock_action = new List<ActionMsg>();
                    weapon_lock_action.Add(new ActionMsg { type = (int)ActionType.WeaponLock, obj_id = obj_id });// 动作类型、算子id
                    individualValidActions.Add((int)ActionType.WeaponLock, weapon_lock_action);// 动作集合添加进合法动作以该动作类型为键的值中
                }
            }

            // 判断能否展开武器
            if (weapon_unfold_state == 0)// 武器已经锁定
            {
                if (stop & speed <= 0 & move_to_stop_remain_time <= 0 & weapon_unfold_time <= 0 && change_state_remain_time <= 0)// 没有在执行其他动作
                {
                    List<ActionMsg> weapon_unfold_action = new List<ActionMsg>();
                    weapon_unfold_action.Add(new ActionMsg { type = (int)ActionType.WeaponUnfold, obj_id = obj_id });// 动作类型、算子id
                    individualValidActions.Add((int)ActionType.WeaponUnfold, weapon_unfold_action);// 动作集合添加进合法动作以该动作类型为键的值中
                }
            }
            return individualValidActions;// 返回全部合法动作
        }

        private void PutForwardObservation(Map map)
        {
            // 倒计时
            if (change_state_remain_time > 0)  // 切换状态倒计时
            {
                if (keep && target_state == MoveStateType.Shelt)    //被压制，中断掩蔽
                {
                    change_state_remain_time = 0;// 中断计时
                    target_state = move_state;// 目标状态恢复为当前状态
                }
                else
                {
                    change_state_remain_time--;
                    if (change_state_remain_time <= 0)// 完成计时
                    {
                        move_state = target_state;// 当前状态切换为目标状态
                    }
                }
            }
            if (weapon_cool_time > 0)  // 武器冷却倒计时
            {
                weapon_cool_time--;
            }
            if (weapon_unfold_time > 0)  // 武器展开/锁定倒计时
            {
                weapon_unfold_time--;
                if (weapon_unfold_time <= 0)// 完成计时
                {
                    weapon_unfold_state = 1 - weapon_unfold_state;// 切换状态（1 - 1 = 0; 1 - 0 = 1）1为展开，0为锁定
                }
            }
            if (keep_remain_time > 0)//压制倒计时
            {
                keep_remain_time--;
                if (keep_remain_time <= 0)// 计时结束
                {
                    keep = false;// 不再被压制
                }
            }
        }

        private void UpdateChangeStateAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.ChangeState)
            {
                return;
            }
            ChangeStateJudgeResult changeStateJudgeResult = (ChangeStateJudgeResult)judge_result;// 强转为切换状态裁决结果
            target_state = changeStateJudgeResult.TargetState;// 保存要转换的目标状态
            if (move_state == MoveStateType.Shelt && target_state == MoveStateType.Normal) move_state = target_state;// 掩蔽转正常机动不需要倒计时
            else if (move_state == MoveStateType.HalfSpeed && target_state == MoveStateType.Normal) move_state = target_state;// 半速转正常机动不需要倒计时
            else if ((move_state == MoveStateType.Shelt || move_state == MoveStateType.Normal) && target_state == MoveStateType.HalfSpeed) move_state = target_state;// 转半速不需要倒计时
            else change_state_remain_time = 76;// 其他都需要75秒倒计时（76在进入倒计时代码时会减一，变成75）（先更新裁决结果再更新持续性动作，是为了下达机动之后能立马就动起来？）
        }

        private void UpdateWeaponLockAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.WeaponLock)
            {
                return;
            }
            weapon_unfold_time = 76;// 武器展开/锁定倒计时
        }
        private void UpdateWeaponUnfoldAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.WeaponUnfold)
            {
                return;
            }
            weapon_unfold_time = 76;// 武器展开/锁定倒计时
        }

        private void UpdateShootAttris(IJudgeResult judge_result)
        {
            if (!judge_result.IsSuccess) return;// 没成功，跳过
            if (judge_result.ActionType != ActionType.Shoot || judge_result.ActionType != ActionType.GuideShoot)
            {
                return;
            }
            // 炮兵没有主动攻击某个目标的动作，所以只能是被射击
            int damage = (int)judge_result.GetType().GetProperty("Damage").GetValue(judge_result);// 取得裁决结果中的最终战损
            int targetObjID = (int)judge_result.GetType().GetProperty("TargetObjID").GetValue(judge_result);// 取得裁决结果中的攻击目标
            if (targetObjID == obj_id)// 如果攻击目标是本算子
            {
                if (blood > damage)// 如果当前血量大于伤害值，即还活着
                {
                    blood -= damage;// 扣除生命值
                    keep = true;// 被攻击就被压制
                    keep_remain_time = 151;// 压制剩余时间
                    if (change_state_remain_time > 0 && target_state == MoveStateType.Shelt)//被压制，中断掩蔽
                    {
                        change_state_remain_time = 0;
                        target_state = move_state;
                    }
                }
                else blood = 0;// 如果当前血量小于大于伤害值，血量为0
            }
        }

        private void UpdateJMPlanAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.JMPlan)
            {
                return;
            }
            weapon_cool_time = 301;// 间瞄冷却时间
        }

        private void UpdateCancelJMPlanAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.CancelJMPlan)
            {
                return;
            }
            weapon_cool_time = 0;// 取消之后，不用继续冷却
        }

        private void UpdataStackAttris(List<IOperator> oprs)
        {
            int stack_count = 0;// 记录本算子当前所在的六角格一共有多少算子
            for (int i = 0; i < oprs.Count; i++)
            {
                if (!typeof(IMoveAttris).IsAssignableFrom(oprs[i].GetType())) continue;// 没有cur_hex属性，跳过

                int other_hex = (int)oprs[i].GetType().GetProperty("CurHex").GetValue(oprs[i]);
                if (cur_hex == other_hex)// 如果在同一个六角格
                {
                    Color other_color = (Color)oprs[i].GetType().GetProperty("Color").GetValue(oprs[i]);// 颜色
                    OprType other_type = (OprType)oprs[i].GetType().GetProperty("Type").GetValue(oprs[i]);// 细分类型
                    if (color == other_color && (other_type == OprType.Vehicle || other_type == OprType.Infantry)) stack_count++;// 如果己方地面算子，stack_count加一
                }
            }
            if (stack_count > 1) stack = true;// 如果有己方其他地面算子，则为堆叠状态
            else stack = false;// 否则不为堆叠
        }
        private void UpdataSeeEnemyAttris(List<IOperator> oprs, Map map)
        {
            if (observe_distance == null) return;// 如果观察距离属性为空，不作判断

            if (see_enemy_bop_ids == null) see_enemy_bop_ids = new List<int>();// 初始化see_enemy_bop_ids
            else see_enemy_bop_ids.Clear();
            for (int i = 0; i < oprs.Count; i++)
            {
                if (!typeof(ICommonAttris).IsAssignableFrom(oprs[i].GetType()) ||
                    !typeof(IMoveAttris).IsAssignableFrom(oprs[i].GetType())) continue;// 没有必要的属性，跳过

                Color enemy_color = (Color)oprs[i].GetType().GetProperty("Color").GetValue(oprs[i]);
                OprType enemy_type = (OprType)oprs[i].GetType().GetProperty("Type").GetValue(oprs[i]);
                int enemy_hex = (int)oprs[i].GetType().GetProperty("CurHex").GetValue(oprs[i]);
                OprSubType enemy_sub_type = (OprSubType)oprs[i].GetType().GetProperty("Subtype").GetValue(oprs[i]);
                MoveStateType enemy_move_state = (MoveStateType)oprs[i].GetType().GetProperty("MoveState").GetValue(oprs[i]);

                if (color == enemy_color) continue;// 己方算子，跳过

                if (map.CanSeeTerrain(type, enemy_type, cur_hex, enemy_hex, enemy_sub_type, observe_distance, enemy_move_state))// 可以看见
                {
                    see_enemy_bop_ids.Add(oprs[i].ObjID);// 将此算子id加进see_enemy_bop_ids
                }
            }
        }
    }
}
